# 此文件实现对采集到的信号进行 FFT 变换、频域滤波和傅里叶反变换，并通过 DAC 回放信号
import ADC0832                   # 导入 ADC0832 模块
import DAC_TLC5620 as DAC        # 导入 DAC_TLC5620 模块
import wiringpi                  # 导入 wiringpi 模块
import time                      # 导入时间模块
import numpy as np               # 导入 NumPy 模块
import matplotlib.pyplot as plt  # 导入 Matplotlib 模块

# 初始化 ADC0832 和 DAC_TLC5620 模块
def init():
    ADC0832.setup()
    DAC.setup()
    
# 主循环，进行信号处理和回放
def loop():
    # 先做 FFT
    fft_size=256       # 256 点 FFT
    sampl_freq=4500    # 采样频率为 4500Hz

    # 下截止频率
    freq_low=0         # 低频截止频率
    # 上截止频率
    freq_high=500      # 高频截止频率
    n=0
    y=[]
    t_sample=1/sampl_freq
    t=time.time()
    t0_start=t
    while n<fft_size: # 进行信号采样，共 256 点数据
        # 读取 ADC0832 的数字量
        if n>0:
            dt=time.time()-t0_start
            tmp=int(1000000*(t_sample*(n+1) - dt))
            if tmp>0:
                wiringpi.delayMicroseconds(int(1000000*(t_sample*(n+1) - dt))) # 每次延时后测量
        digitalVal=ADC0832.getResult()
        n=n+1
        y.append(3.3*float(digitalVal)/255)
    t=time.time()-t                 # 256 点采样时间    
    sampl_freq2= fft_size/t         # 计算实际采样频率
    print("real sample_freq: %d" % sampl_freq2)
    
    y_fft=np.fft.fft(y)             # 进行 FFT 变换
    y_fft_ampl=np.abs(y_fft)        # 计算幅度谱
    x=np.linspace(0,t,fft_size)
    freq=np.linspace(-sampl_freq/2,sampl_freq/2,fft_size)

    # 归一化处理
    low_pos=freq_low*fft_size/sampl_freq  
    high_pos=freq_high*fft_size/sampl_freq 

    high_neg=fft_size-high_pos
    low_neg=fft_size-low_pos 
    i=1
    smooth_fft=[y_fft[0]]  # 保留直流分量
    while i<fft_size:  # 频域滤波
        # 截掉下截至频率以下的信号
        if i<low_pos:  
            smooth_fft.append(0)
            i=i+1
            continue
        # 截掉上截至频率以上的信号
        if i>high_pos and i<high_neg:  
            smooth_fft.append(0)
            i=i+1
            continue
        if i>low_neg:  
            smooth_fft.append(0)
            i=i+1
            continue
        smooth_fft.append(y_fft[i])
        i=i+1
    
    # 对经过频域滤波的信号做傅里叶反变换
    smooth_org=np.fft.ifft(smooth_fft)   
    smooth_fft_ampl=np.abs(smooth_fft)   
    smooth=np.abs(smooth_org)

    # 绘制原始信号和滤波后信号的时域和频域图
    plt.figure(figsize=(8,4))
    plt.subplot(221)
    plt.plot(x,y)
    plt.title(u"Time Domain (Original)") # 绘制原始信号的时域图
    plt.subplot(222)
    plt.plot(freq,np.fft.fftshift(y_fft_ampl))
    plt.title(u"Frequency Domain (Original)") # 绘制原始信号的频域图
    plt.subplot(223)
    plt.plot(x,smooth)
    plt.xlabel(u"t(s)")
    plt.title(u"Time Domain(smoothing)") # 绘制滤波后信号的时域图
    plt.subplot(224)
    plt.plot(freq,np.fft.fftshift(smooth_fft_ampl))
    plt.xlabel(u"freq(Hz)")
    plt.title(u"Frequency Domain(smoothing)") # 绘制滤波后信号的频域图
    plt.subplots_adjust(hspace=0.4)
    plt.show()

    # 通过 DAC 回放信号
    output_count=0
    while 1:    # 输出信号
        output_count+=1
        i=0
        t=time.time()
        t2_start = time.time()
        while i<fft_size: # 输出 256 点数据
            if i>0:
                dt=time.time()-t2_start
                tmp=int(1000000*(t_sample*(i+1) - dt)) 
                if tmp>0:
                    wiringpi.delayMicroseconds(tmp) # 每次延时后发送数据
            DAC.SendOneData(int(smooth[i]*255/3.3))
            i=i+1
        if output_count==1:
            t=time.time()-t             # 256 点采样时间    
            dac_freq= fft_size/t        # 计算实际 DAC 输出频率
            print("real dac_freq: %d" % dac_freq)

if __name__=='__main__':
    init()              # 初始化 ADC0832 和 DAC_TLC5620 模块
    loop()              # 进行信号处理和回放
    ADC0832.destroy()   # 释放 ADC0832 GPIO 端口
    DAC.destroy()       # 释放 DAC_TLC5620 GPIO 端口
    print("The end!")   # 程序终止